package com.eli.pingserver

import cn.hutool.core.date.DateTime
import cn.hutool.core.util.StrUtil
import cn.hutool.cron.CronUtil
import cn.hutool.db.ds.DSFactory
import cn.hutool.db.handler.EntityListHandler
import cn.hutool.db.sql.SqlExecutor
import cn.hutool.extra.mail.MailUtil
import com.eli.pingserver.entities.ServerSurviveInfo
import com.eli.pingserver.enums.ServerStatus
import com.eli.pingserver.utils.ToMailUtil
import com.eli.pingserver.utils.NetUtil
import javax.sql.DataSource

/**
 * ping runner
 * @author eli
 */
class PingRunner : Runnable {

    companion object {
        // 获取默认数据源
        private val ds: DataSource = DSFactory.get()

        // 数据库表名
        private const val TABLE_NAME = "server_survive_info"

        @JvmStatic
        fun main(args: Array<String>) {
            CronUtil.start()
            println("--------------------心跳检测启动--------------------")
        }

        /**
         * ping
         */
        fun ping(errorNumber: Int, ip: String?): Boolean {
            if (ip == null) return false

            var pingError = errorNumber
            if (!ping(ip)){
                pingError -= 1
                if (pingError >= 0){
                    ping(pingError, ip)
                }else{
                    return false
                }
            }
            return true
        }

        fun ping(ip: String): Boolean {
            // 首先校验ip地址格式
            if (!NetUtil.checkFormat(ip)) return false

            // 获取操作系统
            val command = if (NetUtil.hasWinOS()) {
                String.format(NetUtil.PING_WIN_ONCE, ip)
            } else {
                String.format(NetUtil.PING_UNIX_ONCE, ip)
            }
            val p1 = Runtime.getRuntime().exec(command)
            val returnVal = p1.waitFor()
            return returnVal == 0
        }
    }


    /**
     * project main entrance
     */
    override fun run() {
        val connection = ds.connection

        connection.use { connection ->
            // 获取数据库中数据
            val sql = "select * from $TABLE_NAME"
            val bdEntities = SqlExecutor.query(connection, sql, EntityListHandler())

            bdEntities.forEach {
                val now = DateTime.now().toString()

                // 转换为对象
                val surviveInfo = ServerSurviveInfo.entity2ServerSurviveInfo(it)

                println("$now  心跳检测...【服务器】: ${surviveInfo.serverName}----【ip】: ${surviveInfo.serverIp}")

                // 测试 ping
                val ip = surviveInfo.serverIp

                if (ping(3, ip)) {
                    surviveInfo.status = ServerStatus.NORMAL.code
                    surviveInfo.updatedTime = now
                } else {
                    surviveInfo.status = ServerStatus.UNUSUAL.code
                    surviveInfo.updatedTime = now

                    // 发送邮件
                    val message = String.format(ToMailUtil.message, surviveInfo.serverIp)
                    MailUtil.send(ToMailUtil.addressee,"服务器异常", message,false)

                }
                SqlExecutor.execute(connection, ServerSurviveInfo.getUpdateStatusSQL(surviveInfo))
            }
            println("-------------------------------------------------")
        }
    }


}